using OfficeOpenXml;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace Super
{
	public static class EditorUtil
	{

		/*****************************************Excel相关操作*******************************************/
		/// <summary>
		/// 读取Excel表格数据，并存储到SO中
		/// </summary>
		/// <param name="node"></param>
		/// <param name="sheetIndex"></param>
		public static void ReadExcelToSO(ExcelNoteNode node, int sheetIndex)
		{
			Type typeSO = ExcelNoteSO.Ins.GetTableClassType(node, sheetIndex);
			Type typeData = ExcelNoteSO.Ins.GetTableNodeType(node, sheetIndex);
			ExcelTableInfo info = ExcelUtil.GetTableInfo(node.excelPath, sheetIndex);
			var excelAsset = AssetDatabase.LoadAssetAtPath(node.SOPaths[sheetIndex], typeSO);
			if (excelAsset == null)
			{
				excelAsset = ScriptableObject.CreateInstance(typeSO);
				AssetUtil.TryCreatDirectory(node.SOPaths[sheetIndex]);
				AssetDatabase.CreateAsset(excelAsset, node.SOPaths[sheetIndex]);
				string groupName = FWConfig.excelCfgAGroup;
				AssetUtil.ACreateOrMove(groupName, node.SOPaths[sheetIndex]);
				AssetDatabase.SaveAssets();
				AssetDatabase.Refresh();
			}

			typeSO.GetField("fieldNames").SetValue(excelAsset, info.fieldNames);
			typeSO.GetField("fieldTypes").SetValue(excelAsset, info.fieldTypes);
			typeSO.GetField("keys").SetValue(excelAsset, info.keys.ToArray());
			typeSO.GetField("keyTypes").SetValue(excelAsset, info.keyTypes.ToArray());
			typeSO.GetMethod("Clear").Invoke(excelAsset, null);
			MethodInfo typeSO_AddNodeData = typeSO.GetMethod("AddNodeData");

			string[][] allRowData = info.data.Skip(info.ignoreRow).ToArray();
			foreach (var rowData in allRowData)
			{
				string[] data = rowData.Skip(info.ignoreCol).ToArray();

				var obj = Activator.CreateInstance(typeData);
				typeData.GetMethod("SetValue").Invoke(obj, new object[] { data });
				typeSO_AddNodeData.Invoke(excelAsset, new object[] { obj });
			}

			if (info.hasKey)
			{
				MethodInfo typeSO_SaveExcelDictionary = typeSO.GetMethod("SaveExcelDictionary");
				typeSO_SaveExcelDictionary.Invoke(excelAsset, null);
			}

			if (info.hasLang)
			{
				HashSet<string> langSet = LangUtil.GetExcelNewKeys(info);
				LangUtil.AddKeys(langSet, FWConfig.excelLangKeyPath);
				LogUtil.Log(LogType.Normal, LogCategory.Lang, $"{node.excelPath}_{node.TableNames[sheetIndex]} 表格多语言处理");
			}

			EditorUtility.SetDirty(excelAsset);
		}

		/// <summary>
		/// 使用SO的内容，并覆写Excel文件
		/// LookAt ExcelPackage 里面的数组从1开始：坑啊
		/// </summary>
		/// <param name="node"></param>
		/// <param name="sheetIndex"></param>
		public static void WriteSOToExcel(ExcelNoteNode node, int sheetIndex)
		{
			string excelAbsolutePath = GlobalUtil.GetAbsolutePath(node.excelPath);
			FileInfo excelFile = new FileInfo(excelAbsolutePath);
			ExcelPackage package = new ExcelPackage(excelFile);
			ExcelWorksheet worksheet = package.Workbook.Worksheets[sheetIndex + 1];
			ExcelTableInfo info = ExcelUtil.GetTableInfo(node.excelPath, sheetIndex);
			Type typeSO = ExcelNoteSO.Ins.GetTableClassType(node, sheetIndex);

			var excelAsset = AssetDatabase.LoadAssetAtPath(node.SOPaths[sheetIndex], typeSO);
			var data = typeSO.GetField("data").GetValue(excelAsset);
			IList dataList = (IList)data;
			string[] rowData;
			for (int i = 0; i < dataList.Count; i++)
			{
				var item = dataList[i];
				item.GetType().GetMethod("ValueBackFill").Invoke(item, null);
				rowData = (string[])item.GetType().GetField("rowData").GetValue(item);
				for (int j = 0; j < rowData.Length; j++)
				{
					worksheet.SetValue(i + info.ignoreRow + 1, j + info.ignoreCol + 1, rowData[j]);
				}
			}
			//修改某一格的数据
			//worksheet.Cells[4, 3].Value = "女";
			//worksheet.SetValue(4, 3, "女");
			//保存excel
			package.Save();
		}

		public static void LoadExcel(string excelPath)
		{
			if (string.IsNullOrEmpty(excelPath))
			{
				LogUtil.Log(LogType.Normal, LogCategory.Excel, "Excel路径不能为空");
				return;
			}

			ExcelNoteNode node = ExcelNoteSO.Ins.FindTableInfo(excelPath);
			for (int i = 0; i < node.TableNames.Count; i++)
			{
				EditorUtil.ReadExcelToSO(node, i);
			}
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "导入" + excelPath + "表格");
		}
		public static void LoadAllExcel()
		{
			foreach (var item in ExcelNoteSO.Ins.Notes)
			{
				LoadExcel(item.excelPath);
			}
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "重新导入所有表格");
		}
		public static void GenerateExcelStructure(string excelPath)
		{
			if (string.IsNullOrEmpty(excelPath))
			{
				LogUtil.Log(LogType.Normal, LogCategory.Excel, "Excel路径不能为空");
				return;
			}

			ExcelNoteNode node = ExcelNoteSO.Ins.SetTableInfo(excelPath);
			for (int i = 0; i < node.TableNames.Count; i++)
			{

				ExcelTableInfo info = ExcelUtil.GetTableInfo(excelPath, i);
				if (info.keys.Contains("enumName"))
				{
					LogUtil.Log(LogType.Warn, LogCategory.Excel, excelPath + "表格包含enumName主键，请选择其他表格");
					return;
				}
				string customData = TextUtil.GetExcelClassText(info);
				AssetUtil.CreateFile(info.tablePath, customData);
			}
			AssetDatabase.Refresh();
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "成功生成" + excelPath + "表格的数据类");
		}

		public static void GenerateExcelEnum(string excelPath)
		{
			if (string.IsNullOrEmpty(excelPath))
			{
				LogUtil.Log(LogType.Normal, LogCategory.Excel, "Excel路径不能为空");
				return;
			}

			List<string> tableNames = ExcelUtil.GetExcelTableNames(excelPath);
			for (int i = 0; i < tableNames.Count; i++)
			{
				ExcelTableInfo info = ExcelUtil.GetTableInfo(excelPath, i);
				if (!info.keys.Contains("enumName"))
				{
					LogUtil.Log(LogType.Warn, LogCategory.Excel, excelPath + "表格无enumName主键，无法生成枚举文件，请选择其他表格");
					return;
				}
				string customData = TextUtil.GetExcelEnumText(info);
				string path = string.Format(FWConfig.excelEnumPath, tableNames[i]);
				AssetUtil.CreateFile(path, customData);
			}
			AssetDatabase.Refresh();
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "成功生成" + excelPath + "表格的枚举");
		}

		public static void RemoveExcelSO(string excelPath)
		{
			ExcelNoteSO.Ins.Remove(excelPath);
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "移除" + excelPath + "的Asset文件");
		}

		public static void RemoveAllExcelSO()
		{
			foreach (var item in ExcelNoteSO.Ins.Notes)
			{
				RemoveExcelSO(item.excelPath);
			}
			ExcelNoteSO.Ins.Notes.Clear();
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "移除所有Excel的Asset文件");
		}

		public static void WriteExcel(string excelPath)
		{
			ExcelNoteNode node = ExcelNoteSO.Ins.FindTableInfo(excelPath);
			for (int i = 0; i < node.TableNames.Count; i++)
			{
				EditorUtil.WriteSOToExcel(node, i);
			}
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "覆写" + excelPath + "文件");
		}

		public static void WriteAllExcel()
		{
			foreach (var item in ExcelNoteSO.Ins.Notes)
			{
				WriteExcel(item.excelPath);
			}
			LogUtil.Log(LogType.Normal, LogCategory.Excel, "所有Asset文件覆写Excel!!!");
		}

	}
}
